package org.dreamwork.jasmine2.javac.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.HashMap;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-1-21
 * Time: 14:46:09
 */
public class ConfigurationParser {
    private static DocumentBuilder builder;
    private static final Logger logger = LoggerFactory.getLogger (ConfigurationParser.class);

    private static Map controls = new HashMap ();

    static {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance ();
        try {
            builder = dbf.newDocumentBuilder ();
        } catch (ParserConfigurationException ex) {
            logger.error (ex.getMessage (), ex);
        }
    }

    public synchronized static void parse () throws IOException, SAXException {
        ClassLoader loader = ConfigurationParser.class.getClassLoader ();
        parse (loader);
    }

    public synchronized static void parse (ClassLoader loader) throws IOException, SAXException {
        Enumeration e = loader.getResources ("META-INF/jasmine.component.xml");
        while (e.hasMoreElements ()) {
            URL url = (URL) e.nextElement ();
            parse (url);
        }
    }

    public static ControlConfiguration getControl (String uri, String name) {
        Map map = (Map) controls.get (uri);
        if (map == null) return null;
        return (ControlConfiguration) map.get (name.trim ().toUpperCase ());
    }

    @SuppressWarnings ("unchecked")
    private static void parse (URL url) throws IOException, SAXException {
        if (builder == null) throw new IOException ("Can't parse configuration");
        InputStream in = url.openStream ();
        try {
            Document doc = builder.parse (in);
            Element root = doc.getDocumentElement ();
            NodeList container = root.getElementsByTagName ("jasmine-controls");
            for (int j = 0; j < container.getLength (); j ++) {
                Element e = (Element) container.item (j);
                String uri = e.getAttribute ("uri");
                Map map = (Map) controls.get (uri);
                if (map == null) {
                    map = new HashMap ();
                    controls.put (uri, map);
                }
                NodeList list = e.getElementsByTagName ("control");
                for (int i = 0; i < list.getLength (); i++) {
                    Element ex = (Element) list.item (i);
                    parse (ex, map);
                }
            }
        } finally {
            if (in != null) in.close ();
        }
    }

    @SuppressWarnings ("unchecked")
    private static void parse (Element e, Map map) {
        ControlConfiguration cc = new ControlConfiguration ();
        cc.name = e.getAttribute ("name");
        cc.className = e.getAttribute ("class");
        String template = e.getAttribute ("template");
        if (template != null) {
            try {
                cc.template = Boolean.valueOf (template);
            } catch (Exception ex) {
                // ignore
            }
        }
        NodeList list = e.getElementsByTagName ("support-events");
        if (list != null && list.getLength () > 0) {
            Element events = (Element) list.item (0);
            list = events.getElementsByTagName ("event");
            for (int i = 0; i < list.getLength (); i++) {
                Element event = (Element) list.item (i);
                String name = event.getAttribute ("name");
                String s_is_default = event.getAttribute ("is-default");
                cc.addEvent (name);
                if (s_is_default != null && s_is_default.equalsIgnoreCase ("true"))
                    cc.defaultEvent = name;
            }
        }

        list = e.getElementsByTagName ("binding-properties");
        if (list != null && list.getLength () > 0) {
            Element mapping = (Element) list.item (0);
            list = mapping.getElementsByTagName ("map");
            for (int i = 0; i < list.getLength (); i++) {
                Element m = (Element) list.item (i);
                String attribute = m.getAttribute ("attribute");
                String property = m.getAttribute ("property");
                String s_type = m.getAttribute ("binding-type");
                int type;
                if (s_type != null && s_type.equalsIgnoreCase ("list")) type = BindingProperty.BIND_TYPE_LIST;
                else type = BindingProperty.BIND_TYPE_SIMPLE;
                cc.addMapping (attribute, property, type);
            }
        }

        map.put (cc.name.trim ().toUpperCase (), cc);
    }
}